{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Funciones\n",
    "\n",
    "Temas:\n",
    "1. Cómo declara una función\n",
    "2. Duck-typing en Julia\n",
    "3. Funciones mutantes vs. no-mutantes\n",
    "4. Broadcasting"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Cómo declarar una función\n",
    "Julia nos permite definir una función de varias maneras. La primera requiere de las palabras reservadas `function` y `end`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "function sayhi(name)\n",
    "    println(\"Hi $name, it's great to see you!\")\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "function f(x)\n",
    "    x^2\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Y las podemos llamar así"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "sayhi(\"C-3PO\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "f(42)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Alternativamente, las podemos declarar en una sóla línea"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "sayhi2(name) = println(\"Hi $name, it's great to see you!\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "f2(x) = x^2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "sayhi2(\"R2D2\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "f2(42)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finalmente, pudimos declararlas como funciones \"anónimas\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "sayhi3 = name -> println(\"Hi $name, it's great to see you!\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "f3 = x -> x^2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "sayhi3(\"Chewbacca\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "f3(42)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Duck-typing en Julia\n",
    "*\"If it quacks like a duck, it's a duck.\"* \n",
    "*\"Si suena como pato, es un pato\"*\n",
    "<br><br>\n",
    "En Julia, las funciones operaran con el cualquier valor que haga sentido. <br><br>\n",
    "Por ejemplo, `sayhi` funciona con el nombre de este personaje de tele, escrito como entero..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "sayhi(55595472)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Y `f` va a funcionar en una matriz."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "A = rand(3, 3)\n",
    "A"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "f(A)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`f` funcionará con \"hi\" porque `*` para inputs de cadenas como concatenación."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "f(\"hi\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Por el otro lado, `f` no funcionará sobre un vector. A diferencia de `A^2`, la cual es una operación bien definida, el signifiado de `v^2` para un vector, `v`, es ambigua. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "v = rand(3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "f(v)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "## Funciones mutantes vs no-mutantes\n",
    "\n",
    "Por convención, funciones seguidas por un `!` alteran, o bien mutan, sus contenidos y las que carecen de un `!` no lo hacen.\n",
    "\n",
    "Por ejemplo, `sort` y `sort!`.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "v = [3, 5, 2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "sort(v)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "v"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`sort(v)` regresa el arreglo ordenado de `v`, pero `v` no cambia. <br><br>\n",
    "\n",
    "Por otro lado, si corremos `sort!(v)`, el contenido del arreglo es ordenado dentro de `v`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "sort!(v)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "v"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Broadcasting\n",
    "\n",
    "Si ponemos `.` entre el nombre de la funcion y su lista de argumento,<br>\n",
    "le estamos diciendo a la función que se \"difunda\"/haga broadcasting sobre los elementos del input. <br>\n",
    "\n",
    "Primero veamos la diferencia entre `f()` y `f.()`.<br>\n",
    "\n",
    "Primero definimos una nueva matriz `A` que hará la diferencia fácil de observar"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "A = [i + 3*j for j in 0:2, i in 1:3]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "f(A)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Cómo se vio antes, para una matriz, `A`,\n",
    "```\n",
    "f(A) = A^2 = A * A\n",
    "``` \n",
    "\n",
    "`f.(A)` por el otro lado va a regresar un objeto que contiene el cuadrado de `A[i, j]` en su entrada correspondiente."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "B = f.(A)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "A[2, 2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "A[2, 2]^2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "B[2, 2]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Esto significa que para `v`, `f.(v)` está definido, pero no para `f(v)` :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "v = [1, 2, 3]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "f.(v)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "### Ejercicios\n",
    "\n",
    "6.1 En vez de broadcastear `f` sobre `v`,  pudimos haber hecho `v .^ 2`.\n",
    "\n",
    "Sin declarar una nueva funcion, agrega 1 a cada elemento de una matriz de `3x3` llena de `0`'s."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "6.3 Una cifra de César recorre cada letra un número determinado de plazas más adelante en el abecedario. Un corrimiento, o shift, de 1 manda \"A\" a \"B\". Escribe una función llamada `cesar` que toma una cadena como input y un corrimiento y regresa una cadena desencriptada tal que obtengas\n",
    "\n",
    "```julia\n",
    "cesar(\"abc\", 1)\n",
    "\"bcd\"\n",
    "\n",
    "cesar(\"hello\", 4)\n",
    "\"lipps\"\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Julia 0.6.1",
   "language": "julia",
   "name": "julia-0.6"
  },
  "language_info": {
   "file_extension": ".jl",
   "mimetype": "application/julia",
   "name": "julia",
   "version": "0.6.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
